package handler

import (
	"bytes"
	"encoding/json"
	"fmt"
	"image"
	"image/jpeg"
	_ "image/png"
	"os"
	"path"
	"runtime/debug"
	"sort"
	"time"

	myUtils "face_search/src/my_utils"
	"face_search/src/my_utils/commons"

	"github.com/nfnt/resize"
	"github.com/sirupsen/logrus"
)

// func OpencvCutImage(response http.ResponseWriter, request *http.Request) {
func OpencvCutImage() {

	// remoteUrl := request.URL.Query().Get("url")
	remoteUrl := "https://tse4-mm.cn.bing.net/th/id/OIP-C.DC0wE78qRpexHyXsE1Bz6QAAAA?rs=1&pid=ImgDetMain"
	fileName := path.Base(remoteUrl)
	defer func() {
		if info := recover(); info != nil {
			logrus.Error("出现错误：", info, string(debug.Stack()))
		}
	}()

	imageDir := "./image/" + time.Now().Format("20060102")
	createDir(imageDir)
	rawFileAddr := imageDir + "/" + fileName + ".jpeg"
	cutFileAddr := imageDir + "/" + fileName + "_cut.jpeg"

	var rawImage image.Image
	var err error
	// fileCutIsExist := fileIsExist(cutFileAddr)
	// if fileCutIsExist {
	// 	// fileCutBytes, readErr := os.ReadFile(cutFileAddr)
	// 	if readErr == nil {
	// 		// response.Header().Set("Content-Type", "image/jpeg")
	// 		// response.Header().Set("Content-Length", strconv.Itoa(len(fileCutBytes)))
	// 		// response.Write(fileCutBytes)
	// 		return
	// 	} else {
	// 		logrus.Error(commons.GetErrorStack(readErr, "读取人脸图片"+fileName+"_cut.jpeg 失败"))
	// 	}
	// }

	rawFleIsExist := fileIsExist(rawFileAddr)
	if rawFleIsExist {
		rawFile, openErr := os.OpenFile(rawFileAddr, os.O_RDONLY, 0444)
		if openErr == nil {
			rawImage, err = jpeg.Decode(rawFile)
			rawFile.Close()
			if err != nil {
				logrus.Error(commons.GetErrorStack(err, "读取本地缓存图片"+fileName+".jpeg 失败"))
				rawImage = commons.GetUrlImage(remoteUrl, rawFileAddr)
			}
		} else {
			logrus.Error(commons.GetErrorStack(err, "读取本地缓存图片"+fileName+".jpeg 失败"))
			rawImage = commons.GetUrlImage(remoteUrl, rawFileAddr)
		}
	} else {
		rawImage = commons.GetUrlImage(remoteUrl, rawFileAddr)
	}

	if rawImage == nil {
		// responseBody := resultString(403, false, "未找到图片数据", nil)
		// response.Write([]byte(responseBody))

		fmt.Println("未找到图片数据")

		return
	}
	rects := myUtils.DetectImgFace(rawImage)
	if rects == nil || len(rects) == 0 {
		// responseBody := resultString(400, false, "未找到人脸信息", nil)
		fmt.Println("未找到人脸信息")
		// response.Write([]byte(responseBody))
		return
	}
	sort.Slice(rects, func(i, j int) bool {
		return rects[i].Dx()*rects[i].Dy() > rects[j].Dx()*rects[j].Dy()
	})

	var cutImg image.Image
	suspectedFacesTotal := len(rects)
	loop := suspectedFacesTotal / 3
	for i := 0; i < loop; i++ {
		cutImg = myUtils.CutImg(rects[i], rawImage)
		eyeRects := myUtils.DetectImgEye(cutImg)
		if len(eyeRects) >= 2 {
			break
		}
		cutImg = nil
	}

	if cutImg == nil {
		/* responseBody := resultString(400, false, "未找到人脸信息", nil)
		response.Write([]byte(responseBody))
		return */
		// 取最大识别区域
		// cutImg = myUtils.CutImg(rects[0], rawImage)
		// 缩放原图
		cutImg = resize.Resize(800, 0, rawImage, resize.Lanczos3)
	}

	commons.SaveJpeg(cutFileAddr, cutImg)
	jpegBuf := new(bytes.Buffer)
	jpegCnvErr := jpeg.Encode(jpegBuf, cutImg, nil)
	if jpegCnvErr != nil {
		logrus.Error(commons.GetErrorStack(jpegCnvErr, "jpeg转bytes异常"))
	}
	// response.Write(jpegBuf.Bytes())
	// response.Header().Set("Content-Type", "image/jpeg")
}

func createDir(dir string) {
	_, dirErr := os.Stat(dir)
	if dirErr == nil {
	} else if os.IsNotExist(dirErr) {
		_ = os.MkdirAll(dir, os.ModePerm)
	} else {
		logrus.Error(commons.GetErrorStack(dirErr, ""))
	}
}

func fileIsExist(file string) bool {
	_, err := os.Stat(file)
	if err == nil {
		return true
	} else if os.IsNotExist(err) {
		return false
	} else {
		logrus.Error(commons.GetErrorStack(err, ""))
		return false
	}
}

func resultString(code int, success bool, msg string, data interface{}) string {
	rawStruct := &struct {
		Code    int         `json:"code"`
		Success bool        `json:"success"`
		Msg     string      `json:"msg"`
		Data    interface{} `json:"data"`
	}{
		Code:    code,
		Success: success,
		Msg:     msg,
		Data:    data,
	}

	rawString, _ := json.Marshal(rawStruct)
	return string(rawString)
}
